package com.example.kumrulutest;

import java.util.Timer;
import java.util.TimerTask;

import android.app.AlertDialog;
import android.app.Service;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.util.Log;
import android.widget.Toast;

public class TrackerService extends Service implements LocationListener {

	private final Context mContext;

	// flag for GPS status
	boolean isGPSEnabled = false;

	// flag for network status
	boolean isNetworkEnabled = false;

	// flag for GPS status
	boolean canGetLocation = false;

	Location location; // location
	double latitude; // latitude
	double longitude; // longitude
	
	Timer gpsTimer;
	
	Location lastLocation;
	
	long lastprovidertimestamp;
	
	boolean gps_recorder_running = false;
	
	String TAG = getClass().getName();

	// The minimum distance to change Updates in meters
	private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters

	// The minimum time between updates in milliseconds
	private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1; // 1 minute

	// Declaring a Location Manager
	protected LocationManager locationManager;
	

	public TrackerService(Context context) {
		this.mContext = context;
		getLocation();
	}

	public Location getLocation() {
		try {
			locationManager = (LocationManager) mContext
					.getSystemService(LOCATION_SERVICE);

			// getting GPS status
			isGPSEnabled = locationManager
					.isProviderEnabled(LocationManager.GPS_PROVIDER);

			// getting network status
			isNetworkEnabled = locationManager
					.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

			if (!isGPSEnabled && !isNetworkEnabled) {
				// no network provider is enabled
			} else {
				this.canGetLocation = true;
				if (isNetworkEnabled) {
					locationManager.requestLocationUpdates(
							LocationManager.NETWORK_PROVIDER,
							MIN_TIME_BW_UPDATES,
							MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
					Log.d("Network", "Network");
					if (locationManager != null) {
						location = locationManager
								.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
						if (location != null) {
							latitude = location.getLatitude();
							longitude = location.getLongitude();
						} 
					}
				}
				// if GPS Enabled get lat/long using GPS Services
				if (isGPSEnabled) {
					if (location == null) {
						locationManager.requestLocationUpdates(
								LocationManager.GPS_PROVIDER,
								MIN_TIME_BW_UPDATES,
								MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
						Log.d("GPS Enabled", "GPS Enabled");
						if (locationManager != null) {
							location = locationManager
									.getLastKnownLocation(LocationManager.GPS_PROVIDER);
							if (location != null) {
								latitude = location.getLatitude();
								longitude = location.getLongitude();
							}
						}
					}
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

		return location;
	}
	
	/**
	 * Stop using GPS listener
	 * Calling this function will stop using GPS in your app
	 * */
	public void stopUsingGPS(){
		if(locationManager != null){
			locationManager.removeUpdates(TrackerService.this);
		}		
	}
	
	/**
	 * Function to get latitude
	 * */
	public double getLatitude(){
		if(location != null){
			latitude = location.getLatitude();
		}
		
		// return latitude
		return latitude;
	}
	
	/**
	 * Function to get longitude
	 * */
	public double getLongitude(){
		if(location != null){
			longitude = location.getLongitude();
		}
		
		// return longitude
		return longitude;
	}
	
	/**
	 * Function to check GPS/wifi enabled
	 * @return boolean
	 * */
	public boolean canGetLocation() {
		return this.canGetLocation;
	}
	
	/**
	 * Function to show settings alert dialog
	 * On pressing Settings button will lauch Settings Options
	 * */
	public void showSettingsAlert(){
		AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
   	 
        // Setting Dialog Title
        alertDialog.setTitle("GPS is settings");
 
        // Setting Dialog Message
        alertDialog.setMessage("GPS is not enabled. Do you want to go to settings menu?");
 
        // On pressing Settings button
        alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog,int which) {
            	Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            	mContext.startActivity(intent);
            }
        });
 
        // on pressing cancel button
        alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
            dialog.cancel();
            }
        });
 
        // Showing Alert Message
        alertDialog.show();
	}

	@Override
	public void onLocationChanged(Location location) {
	}

	@Override
	public void onProviderDisabled(String provider) {
	}

	@Override
	public void onProviderEnabled(String provider) {
	}

	@Override
	public void onStatusChanged(String provider, int status, Bundle extras) {
	}

	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}
	
	
	
	/**
	 * try to get the 'best' location selected from all providers
	 */
	private Location getBestLocation() {
		
	    Location gpslocation = getLocationByProvider(LocationManager.GPS_PROVIDER);
	    Location networkLocation =
	            getLocationByProvider(LocationManager.NETWORK_PROVIDER);
	    // if we have only one location available, the choice is easy
	    if (gpslocation == null) {
	        Log.d(TAG, "No GPS Location available.");
	        lastLocation = networkLocation;
	        return networkLocation;
	    }
	    if (networkLocation == null) {
	        Log.d(TAG, "No Network Location available");
	        lastLocation = gpslocation;
	        return gpslocation;
	    }
	    // a locationupdate is considered 'old' if its older than the configured
	    // update interval. this means, we didn't get a
	    // update from this provider since the last check
	    long old = System.currentTimeMillis() - getGPSCheckMilliSecsFromPrefs();
	    boolean gpsIsOld = (gpslocation.getTime() < old);
	    boolean networkIsOld = (networkLocation.getTime() < old);
	    // gps is current and available, gps is better than network
	    if (!gpsIsOld) {
	        Log.d(TAG, "Returning current GPS Location");
	        lastLocation = gpslocation;
	        return gpslocation;
	    }
	    // gps is old, we can't trust it. use network location
	    if (!networkIsOld) {
	        Log.d(TAG, "GPS is old, Network is current, returning network");
	        return networkLocation;
	    }
	    // both are old return the newer of those two
	    if (gpslocation.getTime() > networkLocation.getTime()) {
	        Log.d(TAG, "Both are old, returning gps(newer)");
	        lastLocation = gpslocation;
	        return gpslocation;
	    } else {
	        Log.d(TAG, "Both are old, returning network(newer)");
	        lastLocation = networkLocation;
	        return networkLocation;
	    }
	}

	/**
	 * get the last known location from a specific provider (network/gps)
	 */
	private Location getLocationByProvider(String provider) {
	    Location location = null;
	    if (!isProviderSupported(provider)) {
	        return null;
	    }
	    LocationManager locationManager = (LocationManager) getApplicationContext()
	            .getSystemService(Context.LOCATION_SERVICE);
	    try {
	        if (locationManager.isProviderEnabled(provider)) {
	            location = locationManager.getLastKnownLocation(provider);
	        }
	    } catch (IllegalArgumentException e) {
	        Log.d(TAG, "Cannot acces Provider " + provider);
	    }
	    return location;
	}
	
	public void startRecording() {
	    gpsTimer.cancel();
	    gpsTimer = new Timer();
	    long checkInterval = getGPSCheckMilliSecsFromPrefs();
	    long minDistance = getMinDistanceFromPrefs();
	    // receive updates
	    LocationManager locationManager = (LocationManager) getApplicationContext()
	            .getSystemService(Context.LOCATION_SERVICE);
	    for (String s : locationManager.getAllProviders()) {
	        locationManager.requestLocationUpdates(s, checkInterval,
	                minDistance, new LocationListener() {

	                    @Override
	                    public void onStatusChanged(String provider,
	                            int status, Bundle extras) {}

	                    @Override
	                    public void onProviderEnabled(String provider) {}

	                    @Override
	                    public void onProviderDisabled(String provider) {}

	                    @Override
	                    public void onLocationChanged(Location location) {
	                        // if this is a gps location, we can use it
	                        if (location.getProvider().equals(
	                                LocationManager.GPS_PROVIDER)) {
	                            doLocationUpdate(location, true);
	                        }
	                    }
	                });
	        // //Toast.makeText(this, "GPS Service STARTED",
	        // Toast.LENGTH_LONG).show();
	        gps_recorder_running = true;
	    }
	    // start the gps receiver thread
	    gpsTimer.scheduleAtFixedRate(new TimerTask() {

	        @Override
	        public void run() {
	            Location location = getBestLocation();
	            doLocationUpdate(location, false);
	        }
	    }, 0, checkInterval);
	}

	public void doLocationUpdate(Location l, boolean force) {
	    long minDistance = getMinDistanceFromPrefs();
	    Log.d(TAG, "update received:" + l);
	    if (l == null) {
	        Log.d(TAG, "Empty location");
	        if (force)
	            Toast.makeText(this, "Current location not available",
	                    Toast.LENGTH_SHORT).show();
	        return;
	    }
	    if (lastLocation != null) {
	        float distance = l.distanceTo(lastLocation);
	        Log.d(TAG, "Distance to last: " + distance);
	        if (l.distanceTo(lastLocation) < minDistance && !force) {
	            Log.d(TAG, "Position didn't change");
	            return;
	        }
	        if (l.getAccuracy() >= lastLocation.getAccuracy()
	                && l.distanceTo(lastLocation) < l.getAccuracy() && !force) {
	            Log.d(TAG,
	                    "Accuracy got worse and we are still "
	                      + "within the accuracy range.. Not updating");
	            return;
	        }
	        if (l.getTime() <= lastprovidertimestamp && !force) {
	            Log.d(TAG, "Timestamp not never than last");
	            return;
	        }
	    }
	    // upload/store your location here
	}
	
	private long getGPSCheckMilliSecsFromPrefs()
	{
		return 10000;
	}
	
	private long getMinDistanceFromPrefs()
	{
		return 1000;
	}
	
	private boolean isProviderSupported(String provider)
	{
		return true;
	}

}